package com.bnuz.vtl.service;

import com.bnuz.vtl.model.PrivateNode;
import com.bnuz.vtl.model.PublicNode;
import com.bnuz.vtl.repo.PrivateNodeRepo;
import com.bnuz.vtl.repo.PublicNodeRepo;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.annotation.Depth;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PostMapping;

import java.util.*;

@Service
public class PrivateNodeService implements BaseService<PrivateNode, String> {

    @Autowired
    private PrivateNodeRepo privateNodeRepo;
    @Autowired
    private PublicNodeRepo publicNodeRepo;

    @Override
    public PrivateNode save(PrivateNode privateNode) {
        return privateNodeRepo.save(privateNode);
    }

    @Override
    public void deleteById(String privateNodeId) {
        privateNodeRepo.deleteNode(privateNodeId);
    }

    @Override
    public List<PrivateNode> findAll() {
        return privateNodeRepo.findAll();
    }

    @Override
    public PrivateNode findById(String privateNodeId) {
        return privateNodeRepo.findById(privateNodeId).orElse(null);
    }

    public PrivateNode findById(String privateNodeId, int depth) {
        return privateNodeRepo.findById(privateNodeId, depth).orElse(null);
    }

    public void updateWithNewChildren(PrivateNode parent) {
        List<PrivateNode> children = parent.getChildren();
        if (children == null)
            children = new ArrayList<>();
        PrivateNode newChild = new PrivateNode();
        newChild.setName("AC");
        children.add(newChild);
        parent.setChildren(children);
        privateNodeRepo.save(parent);
    }

    public void merge(String publicNodeId, String childName) {
        PublicNode originParent = publicNodeRepo.findById(publicNodeId).orElse(null);
        // 查找该originParent下的所有PrivateNode
        List<PrivateNode> nodes = privateNodeRepo.findPublicNodeLevel1PrivateNode(publicNodeId);
        List<PrivateNode> mergeNodes = privateNodeRepo.findPublicNodeLevel1PrivateNode(publicNodeId);
        // 获取需要merge的PrivateNode
        mergeNodes.removeIf(privateNode -> !privateNode.getName().equals(childName));
        // 获取不需要merge的PrivateNode
        nodes.removeIf(privateNode -> privateNode.getName().equals(childName));
        originParent.setChildPrivateNodes(nodes);

        // 创建新的公有节点
        PublicNode publicNode = new PublicNode();
        publicNode.setPublicNodeId(UUID.randomUUID().toString());
        publicNode.setName(childName);

        // 将原有私有节点下的子节点指向新的公有节点
        List<PrivateNode> newChildren = new ArrayList<>();
        for (PrivateNode privateNode : mergeNodes) {
            PrivateNode realPrivateNode = privateNodeRepo.findByPrivateNodeId(privateNode.getPrivateNodeId());
            if (realPrivateNode.getChildren() != null) {
                newChildren.addAll(realPrivateNode.getChildren());
            }
            realPrivateNode.setChildren(null);
            privateNodeRepo.save(realPrivateNode);
        }

        publicNode.setChildPrivateNodes(newChildren);
        publicNode.setBelongs(mergeNodes);
        publicNodeRepo.save(publicNode);

        // 将新的publicNode 挂在到源publicNode下
        List<PublicNode> publicNodesInOriginParent = originParent.getChildPublicNodes();
        if (publicNodesInOriginParent == null) {
            publicNodesInOriginParent = new ArrayList<PublicNode>();
        }
        publicNodesInOriginParent.add(publicNode);
        originParent.setChildPublicNodes(publicNodesInOriginParent);

        publicNodeRepo.save(originParent);
    }

    public PrivateNode saveNodeAsPublicNodeChildren(String publicNodeId, PrivateNode node) {
        PublicNode publicNode = publicNodeRepo.findById(publicNodeId).orElse(null);
        PrivateNode privateNode = privateNodeRepo.save(node);
        List<PrivateNode> children = publicNode.getChildPrivateNodes();
        if(children == null) {
            children = new ArrayList<>();
        }
        children.add(privateNode);
        publicNode.setChildPrivateNodes(children);
        publicNodeRepo.save(publicNode);
        return privateNode;
    }

    public PrivateNode saveNodeAsPrivateNodeChildren(String privateNodeId, PrivateNode node) {
        PrivateNode parent = privateNodeRepo.findById(privateNodeId).orElse(null);
        PrivateNode privateNode = privateNodeRepo.save(node);
        List<PrivateNode> children = parent.getChildren();
        if(children == null) {
            children = new ArrayList<>();
        }
        children.add(privateNode);
        parent.setChildren(children);
        privateNodeRepo.save(parent);
        return privateNode;
    }

    public PublicNode getParent(String privateNodeId) {
       return publicNodeRepo.findById(privateNodeRepo.getParent(privateNodeId).getPublicNodeId(), -1).orElse(null);
    }

}
